/***********************************************
 * 说明：本文件主要列举Essential C++相关例题与习题
 * ********************************************/
#include "main.h"

void exercise1()
{
    cout << "Please input your name" << endl;
    string first_name, last_name;
    cin >> first_name >> last_name;
    cout << "Hello, " << last_name << first_name << "... and goodbye!" << endl;
}

void exercise2()
{
    string name;
    cout << "Please input your name" << endl;
    cin >> name;
    if (name.size() >= 2) {
        cout << "Hello " << name << endl;
    } else {
        cout << "Sorry, your name is too short" << endl;
    }
}

void exercisr3()
{
    cout << "Please input your name" << endl;
    char name[128];
    cin >> name;
    if (strlen(name) >= 2) {
        printf("Hello %s\n", name);
    } else {
        printf("Sorry your name is too short\n");
    }
}

void exercise4()
{
    int arr[3];
    vector<int>vect;
    for (int i = 0; i<3; i++) {
        cin >> arr[i];
        vect.push_back(arr[i]);
    }
    int sum1 = 0;
    for (int i = 0; i<3; i++) {
        sum1 += arr[i];
    }
    int sum2 = 0;
    for (auto& value : vect) {
        sum2 += value;
    }
    cout << "sum1 = " << sum1 << endl;
    cout << "sum2 = " << sum2 << endl;
    cout << "arr average = " << sum1 / 3 << endl;
    cout << "vector average = " << sum2 / vect.size() << endl;
}

void exercise5()
{
    ifstream input("input.txt");
    vector<string>str;
    string line;
    while(input >> line) {
        cout << line << endl;
        str.push_back(line);
        line = "";
    }
    sort(str.begin(), str.end());
    ofstream output("output.txt");
    if (!output) {
        cout << "optput is failed" << endl;
    } else {
        for (auto content : str) {
            output << content << endl;
        }
    }
}

bool Fibon_elem(int pos, uint32_t& elem)
{
    if (pos <= 0 || pos >1024) {
        elem = 0;
        return false;
    }
    elem = 1;
    int n_1 = 1;
    int n_2 = 1;
    for (int i = 3; i<=pos; i++) {
         elem = n_1 + n_2;
         n_1 = n_2;
         n_2 = elem;
    }
    return true;
}

void exercise6()
{
    int pos;
    cout << "Please input your pos" << endl;
    cin >> pos;
    uint32_t elem = 0;
    if (Fibon_elem(pos, elem)) {
        cout << "element # " << pos << " is " << elem << endl;
    } else {
        cout << "Sorry can not calc pos elem" << endl;
    }
}
/*****************************************
 * 例子7：打印斐波那契数列指定位置前的所有元素
 * **************************************/
bool print_squence(int pos)
{
    if (pos <= 0 || pos >1024) {
        cerr << "invalid pos" << endl;
        return false;
    }
    switch(pos) {
        case 2:
        default:
            cout << "1 ";
        case 1:
            cout << "1 ";
            break;
    }
    int n_1 = 1, n_2 = 1;
    uint32_t elem = 0;
    for (int index = 3; index<=pos; index++) {
        elem = n_1 + n_2;
        n_1 = n_2;
        n_2 = elem;
        // 一行打印10个元素
        cout << elem << (!(index % 10) ? "\n" : " ");
    }
    cout << endl;
    return true;
}

void exercise7()
{
    cout << "please input your pos" << endl;
    int pos = 0;
    cin >> pos;
    if (print_squence(pos)) {
        cout << "this is squence" << endl;
    } else {
        cout << "pos is valid" << endl;
    }
}

/*********************************************
 * 例子8：循环打印斐波那契数列指定位置前的所有元素
 * *******************************************/
void exercise8()
{
    cout << "please input your pos" << endl;
    int pos = 0;
    cin >> pos;
    while(print_squence(pos)) {
        cout << "please input another pos" << endl;
        cin >> pos;
    }
    cout << " input end" << endl;
}
/*************************
 * 例子9：对vector进行排序
 * **********************/
void display(vector<int>vec)
{
    for(auto val : vec) {
        cout << val << " ";
    }
    cout << endl;
}
void swap(int& val1, int& val2)
{
    int temp = val2;
    val2 = val1;
    val1 = temp;
}
void bubble_sort(vector<int>& vec)
{
    for(int i = 0; i<vec.size(); i++) {
        for (int j = i + 1; j<vec.size(); j++) {
            if (vec[i] > vec[j]) {
                swap(vec[i], vec[j]);
            }
        }
    }
}
void exercise9()
{
    int arr[] = { 8, 34, 3, 13, 1, 21, 5, 2};
    vector<int>vec(arr, arr + 8);

    cout << "vector before sort" << endl;
    display(vec);

    bubble_sort(vec);
    
    cout << "vector after sort" << endl;
    display(vec);
}

/*****************************************
 * 例子10：变量的作用域,vector作为函数返回值，
 * 返回的是vector对象，所以外部使用必然出错
 * ***************************************/
void fibon_seq(int size, vector<int>& vec)
{
    if (size <= 0 || size > 1024) {
        cerr << "input size is valid" << endl;
    }
    for (int i = 0; i<size; i++) {
        if (i == 0 || i == 1) {
            vec[i] = 1;
        } else {
            vec[i] = vec[i - 2] + vec[i - 1];
        }
    }
}
void exercise10()
{
    vector<int> vec(4);
    fibon_seq(4, vec);
    display(vec);
}

/*****************************************
 * 例子11：如果想使用vector作为函数返回值，可以
 * 考虑使用静态局部变量
 * ***************************************/
const vector<int>& fibon_seq2(int size)
{
    if (size <= 0 || size > 1024) {
        cerr << "input size is valid" << endl;
    }
    static vector<int>vec;
    for (int i = vec.size(); i<size; i++) {
        if (i == 0 || i == 1) {
            vec.push_back(1);
        } else {
            vec.push_back(vec[i - 2] + vec[i - 1]);
        }
    }
    return vec;
}
void exercise11()
{
    vector<int> vec = fibon_seq2(7);
    display(vec);
}
/*************************
 * 例子12：声明inline函数
 * ***********************/
bool is_size_ok(int size)
{
    const int max_size = 1024;
    if (size <= 0 || size > max_size) {
        cout << "size is valid" << endl;
        return false;
    }
    return true;
}
bool fibon_elem(int size, int pos, int& elem)
{
    const vector<int>vec = fibon_seq2(size);
    if (pos > size) {
        cout << "pos is big than size" << endl;
        return false;
    }
    display(vec);
    elem = vec[pos - 1];
    return true;
}
void exercise12()
{
    int elem;
    bool is_find = fibon_elem(7, 4, elem);
    cout << "pos val is = " << elem << endl;
}
/*************************
 * 例子13：函数提供默认参数
 * ***********************/
void bubble_sort2(vector<int>& vec, ofstream& ofile)
{
    for (int i = 0; i<vec.size(); i++) {
        for (int j = i + 1; j<vec.size(); j++) {
            if (vec[i] > vec[j]) {
                ofile << "about to call swap" << endl;
                swap(vec[i], vec[j]);
            }
        }
    }
}
void bubble_sort3(vector<int>& vec, ofstream* ofile = nullptr)
{
    for (int i = 0; i<vec.size(); i++) {
        for (int j = i + 1; j<vec.size(); j++) {
            if (vec[i] > vec[j]) {
                if (ofile != nullptr) {
                    *ofile << "about to call swap" << endl;
                }
                swap(vec[i], vec[j]);
            }
        }
    }
}
void exercise13()
{    
    // 如下不产生任何信息
    int arr[] = {8, 32, 3, 13, 1, 21, 5, 2};
    vector<int>vec (arr, arr + 8);

    bubble_sort3(vec);
    display(vec);

    // OK：产生调试信息
    int arr1[] = {8, 32, 3, 13, 1, 21, 5, 2};
    vector<int>vec1 (arr1, arr1 + 8);

    ofstream ofile1("output.txt");
    bubble_sort2(vec1, ofile1);
    display(vec1);
}
/*************************
 * 例子14：提供重载函数
 * ***********************/
void display_message(const string& msg, const vector<int>& vec)
{
    cout << msg << endl;
    for (auto val : vec) {
        cout << val;
    }
    cout << endl;
}
void display_message(const string& msg, const vector<char>& vec)
{
    cout << msg << endl;
    for (auto val : vec) {
        cout << val;
    }
    cout << endl;
}
void display_message(const string& msg, const vector<string>& vec)
{
    cout << msg << endl;
    for (auto val : vec) {
        cout << val;
    }
    cout << endl;
}
/*************************
 * 例子15：提供函数模板
 * ***********************/
template<typename type>
void display_message(const string& msg, const vector<type>& vec)
{
    cout << msg << endl;
    for (auto val : vec) {
        cout << val;
    }
    cout << endl;
}

/******************************************************
 * 例子16:Pentagonal数列的求值公式是P(n)=n(3n-1)/2......
 * ****************************************************/
inline bool is_size_ok2(uint32_t size)
{
    if (size < 0 || size > 1024) {
        cout << "size is too large" << endl;
        return false;
    }
    return true;
}
void get_elem(int count, vector<int>& vec)
{
    bool isSizeOk = is_size_ok2(count);
    if (!isSizeOk) {
        return;
    }
    for(int i = 1; i <= count; i++) {
        int res = i * (3 * i - 1) / 2;
        vec.push_back(res);
    }
}
void show_elem(const vector<int>& vec)
{
    for(auto val : vec) {
        cout << val << " ";
    }
    cout << endl;
}
void exercise16()
{
    vector<int>result;
    get_elem(5, result);
    show_elem(result);
}
/******************************************************
 * 例子17:Pentagonal数列的求值公式是P(n)=n(3n-1)/2......
 * 使用局部静态变量
 * ****************************************************/
const vector<int>* get_elem2(uint32_t count)
{
    bool isSizeOk = is_size_ok2(count);
    if (!isSizeOk) {
        return nullptr;
    }
    static vector<int>vec;
    for(int i = 1; i <= count; i++) {
        int res = i * (3 * i - 1) / 2;
        vec.push_back(res);
    }
    return &vec;
}
int show_elem2(int pos)
{
    const vector<int>* vec = get_elem2(pos);
    if (vec == nullptr) {
        cout << "vec is nullptr" << endl;
        return 0;
    }
    int val = (*vec)[pos -1];
    return val;
}
void exercise17()
{
    int val = show_elem2(5);
    cout << "pos val is " << val << endl;
}
/********************
 * 例子18:定义重载函数
 * ******************/
int max(int a, int b)
{
    return (a > b) ? a : b;
}
float max(float a, float b)
{
    return (a > b) ? a : b;
}
char max(char a, char b)
{
    return (a > b) ? a : b;
}
int max(vector<int>& vec)
{
    return (*max_element(vec.begin(), vec.end()));
}
float max(vector<float>& vec)
{
    return (*max_element(vec.begin(), vec.end()));
}
string max(vector<string>& vec)
{
    return (*max_element(vec.begin(), vec.end()));
}
int max(int arr[], int len)
{
    return (*max_element(arr, arr + len));
}
float max(float arr[], int len)
{
    return (*max_element(arr, arr + len));
}
string max(string arr[], int len)
{
    return (*max_element(arr, arr + len));
}
void exercise18()
{
    int val1 = max(2, 4);
    cout << "max(2, 4) = " << val1 << endl;

    int arr[] = {2, 45, 78, 12, 54, 9, 6};
    vector<int>vec = {arr, arr + 7};
    int val2 = max(vec);
    cout << "max(vector<int>) = " << val2 << endl;

    int val3 = max(arr, 7);
    cout << "max(int arr[], int len) = " << val3 << endl;
}
/**************************************
 * 例子19: 使用函数模板重新实现上述max函数
 * ************************************/
template<typename type>
type max(type a, type b)
{
    return (a > b) ? a : b;
}
template<typename type>
type max(vector<type>& vec)
{
    return (*max_element(vec.begin(), vec.end()));
}
template<typename type>
type max(type arr[], int len)
{
    return (*max_element(arr, arr + len));
}
void exercise19()
{
    int val1 = max(7, 12);
    cout << "max(7, 12) = " << val1 << endl;

    int arr[] = {20, 5, 48, 3, 8, 9, 86};
    vector<int>vec = {arr, arr + 7};
    int val2 = max(vec);
    cout << "max(vector<int>) = " << val2 << endl;

    int val3 = max(arr, 7);
    cout << "max(int arr[], int len) = " << val3 << endl;
}
/*******************************************
 * 例子20: 获取vector中指定的元素，并将地址返回
 * *****************************************/
int const* find_1(const vector<int>& vec, int val)
{
    for (int i = 0; i<vec.size(); i++) {
        if (vec[i] == val) {
            return &(vec[i]);
        }
    }
    return 0;
}
template <typename elementType>
elementType const* find_2(const vector<elementType>& vec, elementType val)
{
    for (int i = 0; i<vec.size(); i++) {
        if (vec[i] == val) {
            return &(vec[i]);
        }
    }
    return 0;
}
template <typename elementType>
elementType const* find_3(const elementType* array, int size, elementType val)
{
    if (!array || size == 0) {
        return 0;
    }
    for (int i = 0; i<size; i++) {
        if (array[i] == val) {
            return &(array[i]);
        }
    }
    return 0;
}
template <typename elementType>
elementType const* find_4(const elementType* array, int size, const elementType& val)
{
    if (!array || size == 0) {
        return 0;
    }
    for (int i = 0; i<size; i++, ++array) {
        if (*array == val) {
            return &(array[i]);
        }
    }
    return 0;
}
void exercise20()
{
    vector<int>vec = {1, 3, 4, 2, 7, 45, 12};
    int const* addr = find_3(&vec[0], vec.size(), 4);
    cout << addr << endl;
}
